import random
from stacking.item import Item


def generate_items(nitems, item_stay_distr, due_interval_distr, 
                   order_size=1, rng=random, seed=None, **kwargs):
    """Generate 'nitems' items, using 'item_stay_distr' to define how long each item stays in the 
    warehouse, and 'due_interval_distr' specifies the distribution of intervals between the due 
    dates of consecutive orders, and 'order_size' controls the number of groups of items with the 
    same due date (i.e. orders). Both distribution functions should take the rng as their single 
    argument, and return a value from the distribution."""
    if seed is not None:
        rng.seed(seed)
    # create orders (i.e. groups of items with the same due date)
    norders = int(round(float(nitems) / order_size))
    assert norders > 1
    items, order = make_orders(nitems, norders, rng)
    # generate order due dates
    odue = [None for o in xrange(norders)]
    odue[0] = 0
    for o in xrange(1, norders):
        odue[o] = odue[o-1] + due_interval_distr(rng)
    # generate item due and release dates
    idue = [odue[order[i]] for i in xrange(nitems)]
    irel = [d - max(0.0, item_stay_distr(rng)) for d in idue]
    # adjust dates so that the first release occurs at t=0
    min_t = min(irel)
    irel = [r - min_t for r in irel]
    idue = [d - min_t for d in idue]
    # finally we create and return a list of Item objects
    return [Item(x, r, d) for x, r, d in zip(range(nitems), irel, idue)]
    
    
def make_orders(nitems, norders, rng=random):
    """Create a distribution of 'nitems' items among 'norders' orders, making sure each order has 
    at least one item. All other items are uniformly distributed among orders. This function 
    returns two values: the first is a list of orders, where each order is in turn a list of items;
    the second is a list mapping each item to the order to which the item belongs."""
    order = [None for i in xrange(nitems)]  # order where each item belongs
    items = [[] for o in xrange(norders)]   # items belonging to each order
    def assign(i, o):                       # assign item 'i' to order 'o'
        order[i] = o
        items[o].append(i)
        
    item_list = range(nitems)
    rng.shuffle(item_list)
    for o in xrange(norders):
        assign(item_list.pop(), o)
    for i in item_list:
        assign(i, int(rng.random() * norders))
    return items, order
    
    